package com.linln.common.utils;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class ReflectUtils {
    /**
     * 将orig中非null的属性值复制到dest对应的属性中
     *
     * @param orig
     * @param dest
     */
    public static void copyNotNullProperties(Object orig, Object dest) {
        if (orig == null || dest == null) {
            return;
        }
        for (Class<?> cl = orig.getClass(); cl != Object.class; cl = cl.getSuperclass()) {
            Method[] ms = cl.getDeclaredMethods();
            if (ms != null && ms.length > 0) {
                for (Method m : ms) {
                    String name = m.getName();
                    if (!name.startsWith("get")) {// 获取get方法
                        continue;
                    }
                    try {
                        Object value = m.invoke(orig);
                        if (value == null) {
                            continue;
                        }
                        String propertyName = name.substring(3);
                        propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);

                        BeanUtils.copyProperty(dest, propertyName, value);
                    } catch (Exception e) {
                    }
                }
            }
        }
    }

    /**
     * 获取对象的空属性
     */
    public static Set<String> getNotNullProperties(Object src) {
        if (src == null) {
            return null;
        }
        // 1.获取Bean
        BeanWrapper srcBean = new BeanWrapperImpl(src);
        // 2.获取Bean的属性描述
        PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();
        // 3.获取Bean的空属性
        Set<String> properties = new HashSet<>();
        for (PropertyDescriptor propertyDescriptor : pds) {
            String propertyName = propertyDescriptor.getName();
            Object propertyValue = srcBean.getPropertyValue(propertyName);
            if (propertyValue != null) {
                properties.add(propertyName);
            }
        }
        return properties;
    }


    /**
     * 往对象中设置值，不报错
     *
     * @param arg
     * @param name
     * @param value
     */
    public static void setProperty(Object arg, String name, Object value) {
        try {
            BeanUtils.setProperty(arg, name, value);
        } catch (Exception e) {
        }
    }

    public static void copyProperty(Object src, Object target, String property) {
        try {
            if (src == null || target == null || StringUtils.isBlank(property)) {
                return;
            }
            String getter = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
            Object value = src.getClass().getMethod(getter).invoke(src);
            BeanUtils.setProperty(target, property, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取指定对象中指定属性的值，如果读取失败，则返回null
     *
     * @param entity
     * @param fieldName
     * @return
     */
    public static Object readField(Object entity, String fieldName) {
        if (entity == null || StringUtils.isBlank(fieldName)) {
            return null;
        }
        try {
            String getter = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            Object value = entity.getClass().getMethod(getter).invoke(entity);
            return value;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 把对象中的属性和值转换为map形式存放
     *
     * @param entity
     * @return
     */
    public static Map<String, Object> entityToMap(Object entity) {
        Map<String, Object> returnMap = new HashMap<>();
        if (entity == null) {
            return returnMap;
        }
        Class<?> type = entity.getClass();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = readMethod.invoke(entity);
                    if (result != null) {
                        returnMap.put(propertyName, result);
                    } else {
                        returnMap.put(propertyName, "");
                    }
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | IntrospectionException e) {
            e.printStackTrace();
        }
        return returnMap;
    }

    /**
     * 将对象转换为字符串的键值对
     *
     * @param entity
     * @return
     */
    public static Map<String, String> entityToUrlMap(Object entity, String datePattern) {
        Map<String, String> returnMap = new HashMap<>();
        if (entity == null) {
            return returnMap;
        }
        DateFormat df = new SimpleDateFormat(datePattern);
        Class<?> type = entity.getClass();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = readMethod.invoke(entity);
                    if (result != null) {
                        if (result instanceof Date) {
                            returnMap.put(propertyName, df.format((Date) result));
                        } else {
                            returnMap.put(propertyName, result + "");
                        }
                    } else {
                        returnMap.put(propertyName, "");
                    }
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | IntrospectionException e) {
            e.printStackTrace();
        }
        return returnMap;
    }

    /**
     * 将指定的日志格式化成 yyyy-MM-dd 00:00:00
     *
     * @param time
     * @return
     */
    public static Date processStartTime(Date time) {
        if (time == null) {
            return time;
        }
        return DateUtils.truncate(time, Calendar.DATE);
    }

    /**
     * 将指定的日志格式化成 yyyy-MM-dd 23:59:59
     *
     * @param startTime
     * @return
     */
    public static Date processEndTime(Date time) {
        if (time == null) {
            return time;
        }
        time = DateUtils.addDays(time, 1);
        time = DateUtils.truncate(time, Calendar.DATE);
        return DateUtils.addMilliseconds(time, -1);
    }

    /**
     * 将map中的表字段及值映射到对象中
     *
     * @param row
     * @param entityClass
     * @return
     */
    public static <T> T mapToEntity(Map<String, Object> row, Class<T> entityClass) {
        try {
            T t = entityClass.newInstance();
            for (String field : row.keySet()) {
                Object value = row.get(field);
                if (value == null) {
                    continue;
                }
                StringBuilder name = new StringBuilder();
                boolean splitor = false;
                for (char c : field.toCharArray()) {
                    if (c == '_') {
                        splitor = true;
                        continue;
                    } else {
                        if (splitor) {
                            name.append((c + "").toUpperCase());
                            splitor = false;
                        } else {
                            name.append(c);
                        }
                    }
                }
                try {
                    BeanUtils.setProperty(t, name.toString(), value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
    }

    /**
     * 读取id属性的值
     *
     * @param entity
     * @return
     */
    public static Object getIdValue(Object entity) {
        if (entity == null || entity.getClass().getAnnotation(Entity.class) == null) {
            return null;
        }
        Field idField = getIdField(entity);
        if (idField == null) {
            return null;
        }
        return readField(entity, idField.getName());
    }

    private static Field getIdField(Object entity) {
        Field[] fs = FieldUtils.getAllFields(entity.getClass());
        if (fs == null || fs.length < 1) {
            return null;
        }
        for (Field f : fs) {
            if (f.getAnnotation(Id.class) != null) {
                return f;
            }
        }
        return null;
    }

    /**
     * 获取id属性的字段名称
     *
     * @param entity
     * @return
     */
    @SuppressWarnings("deprecation")
    public static String getIdColumnName(Object entity) {
        if (entity == null || entity.getClass().getAnnotation(Entity.class) == null) {
            return null;
        }
        Field idField = getIdField(entity);
        if (idField == null) {
            return null;
        }
        Column id = idField.getAnnotation(Column.class);
        if (id != null && StringUtils.isNotBlank(id.name())) {
            return id.name();
        } else {
            return ImprovedNamingStrategy.INSTANCE.classToTableName(idField.getName());
        }
    }

    public static void setPropertyToNull(Object entity, String... fields) {
        if (fields == null || fields.length < 1) {
            return;
        }
        for (String f : fields) {
            setProperty(entity, f, null);
        }
    }

}
